"use strict";

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

exports.__esModule = true;
exports["default"] = void 0;

var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));

var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/inheritsLoose"));

var _react = _interopRequireWildcard(require("react"));

var _constant = require("../support/constant");

var _ccContext = _interopRequireDefault(require("../cc-context"));

var util = _interopRequireWildcard(require("../support/util"));

var _getFeatureStrAndStpmapping = _interopRequireDefault(require("../core/base/get-feature-str-and-stpmapping"));

var ev = _interopRequireWildcard(require("../core/event"));

var ccRef = _interopRequireWildcard(require("../core/ref"));

var base = _interopRequireWildcard(require("../core/base"));

var _extractStateByCcsync2 = _interopRequireDefault(require("../core/state/extract-state-by-ccsync"));

var ccClassKey_ccClassContext_ = _ccContext["default"].ccClassKey_ccClassContext_,
    fragmentFeature_classKey_ = _ccContext["default"].fragmentFeature_classKey_,
    computed = _ccContext["default"].computed,
    store = _ccContext["default"].store;
/**
 * 根据connect参数动态的把CcFragment划为某个ccClassKey的实例，同时计算出stateToPropMapping值
 * @param connectSpec 形如: {foo:'*', bar:['b1', 'b2']}
 */

function getFragmentClassKeyAndStpMapping(connectSpec) {
  if (!util.isObjectNotNull(connectSpec)) {
    //代表没有connect到store任何模块的CcFragment
    return {
      ccClassKey: _constant.CC_FRAGMENT_PREFIX + "_0",
      stateToPropMapping: null
    };
  }

  var _getFeatureStrAndStpM = (0, _getFeatureStrAndStpmapping["default"])(connectSpec),
      featureStr = _getFeatureStrAndStpM.featureStr,
      stateToPropMapping = _getFeatureStrAndStpM.stateToPropMapping;

  var ccClassKey = fragmentFeature_classKey_[featureStr];

  if (ccClassKey) {
    return {
      ccClassKey: ccClassKey,
      stateToPropMapping: stateToPropMapping
    };
  } else {
    var oldFragmentNameCount = _ccContext["default"].fragmentNameCount;
    var fragmentNameCount = oldFragmentNameCount + 1;
    _ccContext["default"].fragmentNameCount = fragmentNameCount;
    ccClassKey = _constant.CC_FRAGMENT_PREFIX + "_" + fragmentNameCount;
    fragmentFeature_classKey_[featureStr] = ccClassKey;
    return {
      ccClassKey: ccClassKey,
      stateToPropMapping: stateToPropMapping
    };
  }
}

var cursorKey = _constant.CURSOR_KEY;
var ccSyncKey = _constant.CCSYNC_KEY;

var CcFragment =
/*#__PURE__*/
function (_Component) {
  (0, _inheritsLoose2["default"])(CcFragment, _Component);

  function CcFragment(props, context) {
    var _this;

    _this = _Component.call(this, props, context) || this;
    var ccKey = props.ccKey,
        _props$connect = props.connect,
        connectSpec = _props$connect === void 0 ? {} : _props$connect,
        _props$state = props.state,
        state = _props$state === void 0 ? {} : _props$state;

    var _getFragmentClassKeyA = getFragmentClassKeyAndStpMapping(connectSpec),
        ccClassKey = _getFragmentClassKeyA.ccClassKey,
        stateToPropMapping = _getFragmentClassKeyA.stateToPropMapping;

    var ccUniqueKey = '',
        isCcUniqueKeyAutoGenerated = false;

    if (ccKey) {
      // for CcFragment, if user supply ccKey to props, ccUniqueKey will equal ccKey
      ccUniqueKey = ccKey;
    } else {
      var _base$computeCcUnique = base.computeCcUniqueKey(false, ccClassKey, ccKey, true),
          ck = _base$computeCcUnique.ccKey,
          cuk = _base$computeCcUnique.ccUniqueKey,
          ag = _base$computeCcUnique.isCcUniqueKeyAutoGenerated;

      ccUniqueKey = cuk;
      isCcUniqueKeyAutoGenerated = ag;
      ccKey = ck;
    }

    base.buildCcClassContext(ccClassKey, _constant.MODULE_DEFAULT, [], [], [], [], stateToPropMapping, true);
    ccRef.setRef((0, _assertThisInitialized2["default"])(_this), false, ccClassKey, ccKey, ccUniqueKey, {}, true); // for CcFragment, just put ccClassKey to module's cc class keys

    var moduleName_ccClassKeys_ = _ccContext["default"].moduleName_ccClassKeys_;
    var ccClassKeys = util.safeGetArrayFromObject(moduleName_ccClassKeys_, _constant.MODULE_DEFAULT);
    if (!ccClassKeys.includes(ccClassKey)) ccClassKeys.push(ccClassKey);
    var ctx = ccClassKey_ccClassContext_[ccClassKey];
    var connectedComputed = ctx.connectedComputed || {};
    var connectedState = ctx.connectedState || {};

    var reactForceUpdateRef = _this.forceUpdate.bind((0, _assertThisInitialized2["default"])(_this));

    var reactSetStateRef = _this.setState.bind((0, _assertThisInitialized2["default"])(_this));

    var ccState = {
      module: _constant.MODULE_DEFAULT,
      ccClassKey: ccClassKey,
      ccKey: ccKey,
      ccUniqueKey: ccUniqueKey,
      isCcUniqueKeyAutoGenerated: isCcUniqueKeyAutoGenerated,
      stateToPropMapping: stateToPropMapping,
      renderCount: 0,
      initTime: Date.now()
    };
    _this.cc = {
      // onUrlChanged: null,
      ccState: ccState,
      reactForceUpdate: function reactForceUpdate(cb) {
        ccState.renderCount += 1; //方便用户直接绑定forceUpdate

        if (typeof cb !== 'function') reactForceUpdateRef();else reactForceUpdateRef(cb);
      },
      reactSetState: function reactSetState(state, cb) {
        ccState.renderCount += 1;
        reactSetStateRef(state, function () {
          if (typeof cb !== 'function') reactForceUpdateRef();else reactForceUpdateRef(cb);
        });
      }
    }; // hook implement fo CcFragment

    var __hookMeta = {
      isCcFragmentMounted: false,
      useStateCount: 0,
      useStateCursor: 0,
      stateArr: [],
      useEffectCount: 0,
      useEffectCursor: 0,
      effectCbArr: [],
      effectSeeAoa: [],
      // shouldEffectExecute array of array
      effectSeeResult: [],
      // collect every effect fn's shouldExecute result
      effectCbReturnArr: []
    };
    _this.__hookMeta = __hookMeta;
    var hook = {
      useState: function useState(initialState) {
        var cursor = __hookMeta.useStateCursor;
        var stateArr = __hookMeta.stateArr;
        __hookMeta.useStateCursor++;

        if (__hookMeta.isCcFragmentMounted === false) {
          //render CcFragment before componentDidMount
          __hookMeta.useStateCount++;
          stateArr[cursor] = initialState;
        } else {
          cursor = cursor % __hookMeta.useStateCount;
        }

        var setter = function setter(e) {
          if (e.currentTarget && e.type) {
            var _sync;

            __sync((_sync = {}, _sync[cursorKey] = cursor, _sync), e);
          } else {
            stateArr[cursor] = e;

            _this.cc.reactForceUpdate();
          }
        };

        return [stateArr[cursor], setter];
      },
      useEffect: function useEffect(cb, shouldEffectExecute) {
        var cursor = __hookMeta.useEffectCursor;
        __hookMeta.useEffectCursor++;

        if (__hookMeta.isCcFragmentMounted === false) {
          __hookMeta.effectCbArr.push(cb);

          __hookMeta.effectSeeAoa.push(shouldEffectExecute);

          __hookMeta.useEffectCount++;
        } else {
          // if code running jump into this block, CcFragment already mounted, and now compute result for didUpdate
          cursor = cursor % __hookMeta.useEffectCount;

          if (Array.isArray(shouldEffectExecute)) {
            var len = shouldEffectExecute.length;

            if (len == 0) {
              __hookMeta.effectSeeResult[cursor] = false; // effect fn will been executed only in didMount
            } else {
              // compare prevSee and curSee
              var effectSeeResult = false;
              var prevSeeArr = __hookMeta.effectSeeAoa[cursor];

              if (!prevSeeArr) {
                effectSeeResult = true;
              } else {
                for (var i = 0; i < len; i++) {
                  if (shouldEffectExecute[i] !== prevSeeArr[i]) {
                    effectSeeResult = true;
                    break;
                  }
                }
              }

              __hookMeta.effectSeeAoa[cursor] = shouldEffectExecute;
              __hookMeta.effectSeeResult[cursor] = effectSeeResult;
              if (effectSeeResult) __hookMeta.effectCbArr[cursor] = cb;
            }
          } else {
            __hookMeta.effectSeeResult[cursor] = true; // effect fn will always been executed in didMount and didUpdate

            __hookMeta.effectSeeAoa[cursor] = shouldEffectExecute;
            __hookMeta.effectCbArr[cursor] = cb;
          }
        }
      }
    };
    var dispatcher = ccRef.getDispatcherRef();
    _this.state = state;

    var __sync = function __sync(spec, e) {
      if (spec[cursorKey] !== undefined) {
        //来自hook生成的setter调用
        var _cursor = spec[cursorKey];
        __hookMeta.stateArr[_cursor] = e.currentTarget.value;

        _this.cc.reactForceUpdate();

        return;
      }

      var mockE = base.buildMockEvent(spec, e, _constant.STATE_FOR_ALL_CC_INSTANCES_OF_ONE_MODULE);
      if (!mockE) return; //参数无效

      var currentTarget = mockE.currentTarget;
      var dataset = currentTarget.dataset;
      if (e && e.stopPropagation) e.stopPropagation();

      if (dataset.ccsync.includes('/')) {
        // syncModuleState 同步模块的state状态
        dispatcher.$$sync(mockE);
      } else {
        // syncLocalState 同步本地的state状态
        var _extractStateByCcsync = (0, _extractStateByCcsync2["default"])(dataset.ccsync, currentTarget.value, dataset.ccint, _this.state, mockE.isToggleBool),
            _state = _extractStateByCcsync.state;

        __fragmentParams.setState(_state);
      }
    };

    var __fragmentParams = {
      toggleBool: function toggleBool(e, delay, idt) {
        var _sync$bind;

        if (delay === void 0) {
          delay = -1;
        }

        if (idt === void 0) {
          idt = '';
        }

        if (typeof e === 'string') return __sync.bind(null, (_sync$bind = {}, _sync$bind[ccSyncKey] = e, _sync$bind.type = 'bool', _sync$bind.delay = delay, _sync$bind.idt = idt, _sync$bind));

        __sync({
          type: 'bool'
        }, e);
      },
      //if <Input onChange={(value:string, value2:string)=>void} />
      // <Input onChange={this.sync} /> not work!!!
      // <Input onChange={this.sync('foo/f1')} /> ok
      // only <input data-ccsync="foo/f1" onChange={this.sync} /> ok
      // only <input onChange={this.sync('foo/f1')} /> ok
      sync: function sync(e, val, delay, idt) {
        var _sync$bind2;

        if (delay === void 0) {
          delay = -1;
        }

        if (idt === void 0) {
          idt = '';
        }

        if (typeof e === 'string') return __sync.bind(null, (_sync$bind2 = {}, _sync$bind2[ccSyncKey] = e, _sync$bind2.type = 'val', _sync$bind2.val = val, _sync$bind2.delay = delay, _sync$bind2.idt = idt, _sync$bind2));

        __sync({
          type: 'val'
        }, e);
      },
      // <Input onChange={this.syncInt} /> not work!!!
      // <Input onChange={this.syncInt('foo/bar')} /> ok
      // <input onChange={this.syncInt('foo/bar')} /> ok
      // <input data-ccsync="foo/f1" onChange={this.syncInt('foo/fq')} /> ok
      syncInt: function syncInt(e, delay, idt) {
        var _sync$bind3;

        if (delay === void 0) {
          delay = -1;
        }

        if (idt === void 0) {
          idt = '';
        }

        if (typeof e === 'string') return __sync.bind(null, (_sync$bind3 = {}, _sync$bind3[ccSyncKey] = e, _sync$bind3.type = 'int', _sync$bind3.delay = delay, _sync$bind3.idt = idt, _sync$bind3));

        __sync({
          type: 'int'
        }, e);
      },
      onUrlChanged: function onUrlChanged(cb) {
        _this.cc.onUrlChanged = cb.bind((0, _assertThisInitialized2["default"])(_this));
      },
      connectedComputed: connectedComputed,
      connectedState: connectedState,
      hook: hook,
      emit: function emit(event) {
        for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
          args[_key - 1] = arguments[_key];
        }

        ev.findEventHandlersToPerform.apply(ev, [event, {
          identity: null
        }].concat(args));
      },
      emitIdentity: function emitIdentity(event, identity) {
        for (var _len2 = arguments.length, args = new Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
          args[_key2 - 2] = arguments[_key2];
        }

        ev.findEventHandlersToPerform.apply(ev, [event, {
          identity: identity
        }].concat(args));
      },
      on: function on(event, handler) {
        ev.bindEventHandlerToCcContext(_constant.MODULE_DEFAULT, ccClassKey, ccUniqueKey, event, null, handler);
      },
      onIdentity: function onIdentity(event, identity, handler) {
        ev.bindEventHandlerToCcContext(_constant.MODULE_DEFAULT, ccClassKey, ccUniqueKey, event, identity, handler);
      },
      dispatch: dispatcher.__$$getDispatchHandler(_constant.STATE_FOR_ALL_CC_INSTANCES_OF_ONE_MODULE, _constant.MODULE_DEFAULT, null, null, null, -1, ccKey),
      effect: dispatcher.__$$getEffectHandler(ccKey),
      xeffect: dispatcher.__$$getXEffectHandler(ccKey),
      //seat1, seat2仅仅用于占位
      setModuleState: function setModuleState(module, state, delayMs) {
        dispatcher.$$changeState(state, {
          ccKey: ccKey,
          module: module,
          stateFor: _constant.STATE_FOR_ALL_CC_INSTANCES_OF_ONE_MODULE,
          broadcastTriggeredBy: null,
          delayMs: delayMs
        });
      },
      setGlobalState: function setGlobalState(state, delayMs) {
        dispatcher.$$changeState(state, {
          ccKey: ccKey,
          MODULE_GLOBAL: _constant.MODULE_GLOBAL,
          stateFor: _constant.STATE_FOR_ALL_CC_INSTANCES_OF_ONE_MODULE,
          broadcastTriggeredBy: null,
          delayMs: delayMs
        });
      },
      state: state,
      props: props,
      setState: function setState(state, cb) {
        _this.cc.reactSetState(state, cb);
      },
      forceUpdate: function forceUpdate(cb) {
        _this.cc.reactForceUpdate(cb);
      }
    };
    _this.__fragmentParams = __fragmentParams;
    return _this;
  }

  var _proto = CcFragment.prototype;

  _proto.componentDidMount = function componentDidMount() {
    var _this$__hookMeta = this.__hookMeta,
        effectCbArr = _this$__hookMeta.effectCbArr,
        effectCbReturnArr = _this$__hookMeta.effectCbReturnArr;
    this.__hookMeta.isCcFragmentMounted = true;
    effectCbArr.forEach(function (cb) {
      var cbReturn = cb();

      if (typeof cbReturn === 'function') {
        effectCbReturnArr.push(cbReturn);
      } else {
        effectCbReturnArr.push(null);
      }
    });
  };

  _proto.componentDidUpdate = function componentDidUpdate() {
    var _this$__hookMeta2 = this.__hookMeta,
        effectCbArr = _this$__hookMeta2.effectCbArr,
        effectCbReturnArr = _this$__hookMeta2.effectCbReturnArr,
        effectSeeResult = _this$__hookMeta2.effectSeeResult;
    effectCbArr.forEach(function (cb, idx) {
      var shouldEffectExecute = effectSeeResult[idx];

      if (shouldEffectExecute) {
        var cbReturn = cb();

        if (typeof cbReturn === 'function') {
          effectCbReturnArr[idx] = cbReturn;
        }
      }
    });
  };

  _proto.shouldComponentUpdate = function shouldComponentUpdate() {
    return false;
  };

  _proto.componentWillUnmount = function componentWillUnmount() {
    this.__hookMeta.effectCbReturnArr.forEach(function (cb) {
      if (cb) cb();
    });

    var _this$cc$ccState = this.cc.ccState,
        ccUniqueKey = _this$cc$ccState.ccUniqueKey,
        ccClassKey = _this$cc$ccState.ccClassKey;
    ev.offEventHandlersByCcUniqueKey(ccUniqueKey);
    ccRef.unsetRef(ccClassKey, ccUniqueKey);
    if (_Component.prototype.componentWillUnmount) _Component.prototype.componentWillUnmount.call(this);
  };

  _proto.render = function render() {
    var _this$props = this.props,
        children = _this$props.children,
        render = _this$props.render;
    var view = render || children;

    if (typeof view === 'function') {
      this.__fragmentParams.state = this.state; //注意这里，一定要每次都取最新的

      return view(this.__fragmentParams) || _react["default"].createElement(_react.Fragment);
    } else {
      if (_react["default"].isValidElement(view)) {
        util.justWarning("you are trying to specify a react dom to be CcFragment's children, it will never been rendered again no matter how your state changed!!!");
      }

      return view;
    }
  };

  return CcFragment;
}(_react.Component);

exports["default"] = CcFragment;